Skip to main content

MongoDB module (mongo)

Start here​

bring mongo connects Flow-Wing programs to a MongoDB server via the official libmongoc C driver. The module exposes three classes — mongo::Client, mongo::Collection, and mongo::Cursor — plus a free mongo::lastError() for diagnostics. Documents go in and out as JSON strings, so it pairs naturally with the json module.

Prerequisites: a reachable mongod (default mongodb://127.0.0.1:27017) and a Flow-Wing build with the bundled libmongoc dependency.

A tiny program​

bring mongo

var uri: str = "mongodb://127.0.0.1:27017"
var mc: mongo::Client = new mongo::Client(uri)
if !mc.isOk() {
  println("connect failed: ", mongo::lastError())
  return :
}

var events: mongo::Collection = mc.getCollection("app", "events")
var doc: str = "{\"k\":\"hi\",\"n\":1}"
var ok: bool = events.insertOne(doc)
println("inserted: ", ok)

mc.close()

Note on string literals: Flow-Wing uses double quotes for strings. Escape inner double quotes with backslash when embedding JSON: "{\"key\":\"val\"}".

Connecting​

bring mongo

var mc: mongo::Client = new mongo::Client("mongodb://127.0.0.1:27017")
if !mc.isOk() {
  println("connect failed: ", mongo::lastError())
  return :
}
/; ... use mc ...
mc.close()

new mongo::Client(uri) parses the URI eagerly. isOk() returns false when the URI is invalid or the handle table is full — read mongo::lastError() for the message. Always call close() when done; it destroys the client and every collection/cursor handle the program has opened (the v1 driver uses a single shared handle table).

Getting a collection​

bring mongo

var mc: mongo::Client = new mongo::Client("mongodb://127.0.0.1:27017")
var users: mongo::Collection = mc.getCollection("app", "users")
var events: mongo::Collection = mc.getCollection("app", "events")

getCollection(db, coll) is cheap and does not round-trip to the server — collections are created lazily on first write.

Inserting​

One document​

bring mongo

var coll: mongo::Collection = mc.getCollection("app", "events")
var doc: str = "{\"k\":\"signup\",\"n\":1}"
var ok: bool = coll.insertOne(doc)
if !ok {
  println("insertOne failed: ", mongo::lastError())
}

Many documents​

Pass a JSON array of documents — each element must be an object.

bring mongo

var batch: str = "[{\"k\":\"a\",\"n\":1},{\"k\":\"b\",\"n\":2}]"
var ok: bool = coll.insertMany(batch)
if !ok {
  println("insertMany failed: ", mongo::lastError())
}

Counting​

bring mongo

var n: int64 = coll.count("{\"k\":\"signup\"}")
println("matched: ", n)

/; count all documents — empty filter "" is treated as {}
var total: int64 = coll.count("")

Returns -1 on error; check mongo::lastError().

Reading​

Single document​

bring mongo

var hit: str = coll.findOne("{\"k\":\"signup\"}")
if hit == "" {
  var err: str = mongo::lastError()
  if err != "" {
      println("findOne error: ", err)
  } else {
      println("no match")
  }
} else {
  println("found: ", hit)
}

findOne returns the document as a JSON string in relaxed extended JSON form, or "" for either no match or error — distinguish the two by checking mongo::lastError().

Cursor​

For multiple results, open a cursor with find(filterJson, limit) (pass limit = 0 for no limit). Read with next() until it returns "", then close().

find has no order — pair every limit with findSorted

find returns documents in natural order, which is roughly insertion order: oldest first. Combined with a limit that means you get the oldest n documents, not the newest.

This stays invisible while a collection holds fewer than limit documents, because "the oldest n" and "all of them" are the same set. The moment it grows past limit, the same query silently starts returning stale data — and keeps returning it as new documents pile up behind the cap.

Use findSorted whenever you pass a limit.

bring mongo

var cur: mongo::Cursor = coll.find("{\"k\":\"signup\"}", 100)
var s: str = cur.next()
while s != "" {
  println(s)
  s = cur.next()
}
cur.close()

Always close() cursors to release the server-side cursor and the local handle slot. mc.close() also clears every open cursor as a safety net.

Sorted cursor​

findSorted(filterJson, limit, sortJson) is find with an explicit order. sortJson is a Mongo sort document: -1 is descending, 1 ascending.

bring mongo

/; the 100 MOST RECENT signups, not the 100 oldest
var cur: mongo::Cursor = coll.findSorted("{\"k\":\"signup\"}", 100, "{\"ts\": -1}")
var s: str = cur.next()
while s != "" {
  println(s)
  s = cur.next()
}
cur.close()

With a sort in place, hitting the limit drops the oldest matches — the only end that is safe to lose.

A malformed sortJson is reported through mongo::lastError() and returns an empty cursor. It is never ignored, because silently dropping the sort would put the oldest-first behaviour back with nothing to reveal it.

Error handling​

There are no exceptions. Every operation reports failure through its return value (false, 0, -1, or "") and writes a thread-local string readable via mongo::lastError(). The last-error slot is cleared at the start of every call, so read it immediately after a failing call.

bring mongo

var ok: bool = coll.insertOne("not json")
if !ok {
  println("insert failed: ", mongo::lastError())
}

mongo::Client​

MethodReturnsDescription
new mongo::Client(uri)mongo::ClientOpens a client from a MongoDB connection URI
.isOk()booltrue when the handle is valid
.getCollection(db, coll)mongo::CollectionBorrows a collection handle from this client
.close()—Destroys this client and every open collection/cursor

mongo::Collection​

MethodReturnsDescription
.insertOne(json)boolInserts one JSON document
.insertMany(jsonArr)boolInserts each element of a JSON array of documents
.findOne(filterJson)strFirst match as JSON, or "" for none/error
.find(filterJson, limit)mongo::CursorOpens a cursor in natural order (oldest first); limit = 0 means unlimited
.findSorted(filterJson, limit, sortJson)mongo::CursorSame, with an explicit sort — e.g. "{\\"ts\\": -1}" for newest first
.count(filterJson)int64Document count; -1 on error; "" filter = {}

mongo::Cursor​

MethodReturnsDescription
.next()strNext document as JSON; "" at end-of-stream or error
.close()—Releases the cursor handle

Module function​

FunctionReturnsDescription
mongo::lastError()strMost recent error message (thread-local); "" when none

Limits & gotchas​

  • Single-threaded model — handle tables are global; safe for Flow-Wing's single-thread runtime, not for sharing handles across threads.
  • Handle caps — up to 64 clients, 256 collections, 256 cursors per process.
  • mc.close() is "close-all" — it destroys every open collection and cursor along with the client.
  • JSON in, JSON out — documents cross the FFI as relaxed extended JSON strings; use the json module to build or parse them.
  • limit = 0 on find returns the full result set; on count the filter "" is treated as {}.

Source & tests (if you have the repository)​

WhatWhere
Module sourcefw-modules/mongo_module/mongo-module.fg
Native bridgefw-modules/mongo_module/libflowwing_mongo.cpp
Local smoke testtests/local/mongo_test.fg